#include "packworker.h"
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QDirIterator>
#include <QDebug>
#include <QMutexLocker>
#include <QThread>
#include <QMetaObject>
#include <QCoreApplication>

PackWorker::PackWorker(QObject *parent)
    : QObject(parent)
    , m_cancelled(false)
    , m_totalItems(0)
    , m_currentItem(0)
{
}

PackWorker::~PackWorker()
{
}

void PackWorker::setConfig(const PackConfig& config)
{
    QMutexLocker locker(&m_mutex);
    m_config = config;
}

void PackWorker::setOutputFile(const QString& outputFile)
{
    QMutexLocker locker(&m_mutex);
    m_outputFile = outputFile;
}

void PackWorker::startPacking()
{
    // 重置状态
    {
        QMutexLocker locker(&m_mutex);
        m_cancelled = false;
        m_currentItem = 0;
        m_totalItems = m_config.files.size() + m_config.folders.size();
    }
    
    // 异步执行打包，避免阻塞UI
    QMetaObject::invokeMethod(this, "doPackFiles", Qt::QueuedConnection);
}

void PackWorker::cancelPacking()
{
    QMutexLocker locker(&m_mutex);
    m_cancelled = true;
    emit statusChanged("正在取消打包...");
}

void PackWorker::doPackFiles()
{
    try {
        // 检查是否已取消
        {
            QMutexLocker locker(&m_mutex);
            if (m_cancelled) {
                emit packingFinished(false, "");
                return;
            }
        }
        
        emit statusChanged("正在计算文件总数...");
        
        // 预先计算所有要打包的文件总数
        int totalFiles = 0;
        PackConfig config;
        {
            QMutexLocker locker(&m_mutex);
            config = m_config;
        }
        
        // 计算直接文件数量
        totalFiles += config.files.size();
        
        // 计算文件夹中的文件数量
        for (const QString& folder : config.folders) {
            QString fullPath = QDir(config.source_dir).absoluteFilePath(folder);
            if (QDir(fullPath).exists()) {
                QDirIterator iterator(fullPath, QDirIterator::Subdirectories);
                while (iterator.hasNext()) {
                    iterator.next();
                    QFileInfo fileInfo(iterator.fileInfo());
                    if (fileInfo.isFile()) {
                        totalFiles++;
                    }
                }
            }
        }
        
        // 更新总数
        {
            QMutexLocker locker(&m_mutex);
            m_totalItems = totalFiles;
            m_currentItem = 0;
        }
        
        emit statusChanged(QString("找到 %1 个文件需要打包").arg(totalFiles));
        qDebug() << "总文件数:" << totalFiles;
        
        // 确定输出文件路径
        QString outputPath;
        {
            QMutexLocker locker(&m_mutex);
            if (!m_outputFile.isEmpty()) {
                outputPath = m_outputFile;
            } else {
                outputPath = QDir(config.output_dir).absoluteFilePath(config.output);
            }
        }
        
        emit statusChanged(QString("准备创建ZIP文件: %1").arg(outputPath));
        
        // 确保输出目录存在
        QFileInfo outputInfo(outputPath);
        QDir outputDir = outputInfo.dir();
        if (!outputDir.exists()) {
            emit statusChanged(QString("创建输出目录: %1").arg(outputDir.absolutePath()));
            if (!outputDir.mkpath(".")) {
                emit errorOccurred(QString("无法创建输出目录: %1").arg(outputDir.absolutePath()));
                emit packingFinished(false, "");
                return;
            }
        }
        
        // 检查输出目录是否可写
        if (!outputDir.isReadable()) {
            emit errorOccurred(QString("输出目录不可写: %1").arg(outputDir.absolutePath()));
            emit packingFinished(false, "");
            return;
        }
        
        // 如果文件已存在，先删除
        if (QFile::exists(outputPath)) {
            emit statusChanged("删除现有文件...");
            if (!QFile::remove(outputPath)) {
                emit errorOccurred(QString("无法删除现有文件: %1").arg(outputPath));
                emit packingFinished(false, "");
                return;
            }
        }
        
        // 创建zip文件 - 使用UTF-8编码的路径
        int error = 0;
        zip_t* zipFile = zip_open(outputPath.toUtf8().constData(), ZIP_CREATE | ZIP_TRUNCATE, &error);
        if (!zipFile) {
            char errorBuffer[256];
            zip_error_to_str(errorBuffer, sizeof(errorBuffer), error, errno);
            emit errorOccurred(QString("无法创建ZIP文件: %1, 错误: %2").arg(outputPath, errorBuffer));
            emit packingFinished(false, "");
            return;
        }
        
        emit statusChanged("开始添加文件...");
        emit progressChanged(0);
        
        // 添加文件
        for (const QString& file : config.files) {
            // 短暂休眠以允许信号处理
            QThread::msleep(1);
            
            {
                QMutexLocker locker(&m_mutex);
                if (m_cancelled) {
                    zip_close(zipFile);
                    emit packingFinished(false, "");
                    return;
                }
            }
            
            QString fullPath = QDir(config.source_dir).absoluteFilePath(file);
            emit statusChanged(QString("添加文件: %1").arg(file));
            
            if (!QFile::exists(fullPath)) {
                zip_close(zipFile);
                emit errorOccurred(QString("文件不存在: %1").arg(fullPath));
                emit packingFinished(false, "");
                return;
            }
            
            if (!addFileToZip(zipFile, fullPath, file)) {
                zip_close(zipFile);
                emit errorOccurred(QString("添加文件失败: %1").arg(fullPath));
                emit packingFinished(false, "");
                return;
            }
            
            {
                QMutexLocker locker(&m_mutex);
                m_currentItem++;
                qDebug() << "处理文件" << m_currentItem << "/" << m_totalItems;
                updateProgress(m_currentItem, m_totalItems);
            }
        }
        
        // 添加文件夹
        for (const QString& folder : config.folders) {
            // 短暂休眠以允许信号处理
            QThread::msleep(1);
            
            {
                QMutexLocker locker(&m_mutex);
                if (m_cancelled) {
                    zip_close(zipFile);
                    emit packingFinished(false, "");
                    return;
                }
            }
            
            QString fullPath = QDir(config.source_dir).absoluteFilePath(folder);
            emit statusChanged(QString("添加文件夹: %1").arg(folder));
            
            if (!QDir(fullPath).exists()) {
                zip_close(zipFile);
                emit errorOccurred(QString("文件夹不存在: %1").arg(fullPath));
                emit packingFinished(false, "");
                return;
            }
            
            if (!addFolderToZip(zipFile, fullPath, folder)) {
                zip_close(zipFile);
                emit errorOccurred(QString("添加文件夹失败: %1").arg(fullPath));
                emit packingFinished(false, "");
                return;
            }
        }
        
        emit statusChanged("正在关闭ZIP文件...");
        
        // 关闭zip文件
        int closeResult = zip_close(zipFile);
        if (closeResult != 0) {
            // 获取更详细的错误信息
            zip_error_t* zipError = zip_get_error(zipFile);
            QString errorMsg = QString("无法关闭ZIP文件，错误代码: %1").arg(closeResult);
            if (zipError) {
                errorMsg += QString(", 详细信息: %1").arg(zip_error_strerror(zipError));
            }
            emit errorOccurred(errorMsg);
            emit packingFinished(false, "");
            return;
        }
        
        // 验证文件是否创建成功
        if (!QFile::exists(outputPath)) {
            emit errorOccurred("ZIP文件创建失败：文件不存在");
            emit packingFinished(false, "");
            return;
        }
        
        QFileInfo finalFile(outputPath);
        emit statusChanged(QString("打包完成！文件大小: %1 字节").arg(finalFile.size()));
        emit progressChanged(100);
        emit packingFinished(true, outputPath);
        
    } catch (const std::exception& e) {
        emit errorOccurred(QString("打包过程中发生异常: %1").arg(e.what()));
        emit packingFinished(false, "");
    }
}

bool PackWorker::addFileToZip(zip_t* zipFile, const QString& filePath, const QString& entryName)
{
    // 检查文件是否存在
    if (!QFile::exists(filePath)) {
        return false;
    }
    
    // 使用UTF-8编码的条目名
    QString normalizedEntryName = entryName;
    normalizedEntryName = normalizedEntryName.replace("\\", "/"); // 确保使用正斜杠
    
    // 直接使用文件源，避免内存管理问题
    zip_source_t* source = zip_source_file(zipFile, filePath.toUtf8().constData(), 0, 0);
    if (!source) {
        return false;
    }
    
    zip_int64_t index = zip_file_add(zipFile, normalizedEntryName.toUtf8().constData(), source, ZIP_FL_OVERWRITE);
    if (index < 0) {
        zip_source_free(source);
        return false;
    }
    
    return true;
}

bool PackWorker::addFolderToZip(zip_t* zipFile, const QString& folderPath, const QString& entryName)
{
    QDir dir(folderPath);
    if (!dir.exists()) {
        return false;
    }
    
    QDirIterator iterator(folderPath, QDirIterator::Subdirectories);
    while (iterator.hasNext()) {
        // 短暂休眠以允许信号处理
        QThread::msleep(1);
        
        // 检查是否已取消
        {
            QMutexLocker locker(&m_mutex);
            if (m_cancelled) {
                return false;
            }
        }
        
        QString filePath = iterator.next();
        QFileInfo fileInfo(filePath);
        
        if (fileInfo.isFile()) {
            QString relativePath = dir.relativeFilePath(filePath);
            QString zipEntryName = entryName + "/" + relativePath;
            zipEntryName = zipEntryName.replace("\\", "/"); // 确保使用正斜杠
            
            emit statusChanged(QString("添加文件: %1").arg(zipEntryName));
            
            if (!addFileToZip(zipFile, filePath, zipEntryName)) {
                return false;
            }
            
            // 更新进度
            {
                QMutexLocker locker(&m_mutex);
                updateProgress(++m_currentItem, m_totalItems);
            }
        }
    }
    
    return true;
}

void PackWorker::updateProgress(int current, int total)
{
    if (total > 0) {
        int progress = (current * 100) / total;
        // 直接发送信号，Qt会自动处理线程间的信号传递
        emit progressChanged(progress);
    }
}
